<?php

namespace App\Repository;

use App\Entity\AdminUser;
use App\Entity\Log;
use App\Entity\LogType;
use App\Utils\Base\FilterBase;
use App\Utils\Filter\Admin\System\LogFilter;
use App\Utils\Traits\FilterTrait;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Component\Security\Core\Security;

/**
 * @method Log|null find($id, $lockMode = null, $lockVersion = null)
 * @method Log|null findOneBy(array $criteria, array $orderBy = null)
 * @method Log[]    findAll()
 * @method Log[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
 */
class LogRepository extends ServiceEntityRepository {
    use FilterTrait;

    private $security;

    public function __construct (ManagerRegistry $registry, Security $security) {
        parent::__construct($registry, Log::class);
        $this->security = $security;
    }

    /**
     * User: Gao
     * Date: 2020/4/3
     * Description: 记录日志
     * @param $log_type_id
     * @param $description
     * @param null $parameter
     * @throws \Doctrine\ORM\ORMException
     * @throws \Doctrine\ORM\OptimisticLockException
     */
    public function buildLog ($log_type_id, $description, $parameter = null) {
        $log = new Log();
        $log->setLogTypeId($log_type_id);
        $log->setDescription($description);
        if (!is_null($parameter)) {
            $log->setParameter(serialize($parameter));
        }
        if (is_object($this->security->getUser())) {
            $log->setAdminUserId($this->security->getUser()->getId());
        }
        $log->setIp($this->getClientIp());
        $log->setCreatedAt(new \DateTime());
        $this->getEntityManager()->persist($log);
        $this->getEntityManager()->flush();
    }

    /**
     * User: Gao
     * Date: 2020/4/3
     * Description: 获取客户端IP
     * @return array|false|mixed|string
     */
    private function getClientIp () {
        $ip = '0.0.0.0';

        if (getenv('HTTP_CLIENT_IP')) {
            $ip = getenv('HTTP_CLIENT_IP');
        }
        if (getenv('HTTP_X_REAL_IP')) {
            $ip = getenv('HTTP_X_REAL_IP');
        } elseif (getenv('HTTP_X_FORWARDED_FOR')) {
            $ip = getenv('HTTP_X_FORWARDED_FOR');
            $ips = explode(',', $ip);
            $ip = $ips[0];
        } elseif (getenv('REMOTE_ADDR')) {
            $ip = getenv('REMOTE_ADDR');
        }

        return $ip;
    }

    /**
     * 查询
     * @param array $params
     * @return array|int|string
     */
    public function search ($params = []) {
        $page = $params['page'] ?? 1;
        $limit = $params['limit'] ?? 10;
        return $this->filter(new LogFilter($params))
            ->select(FilterBase::ALIAS.'.id,'.FilterBase::ALIAS.'.log_type_id,'.FilterBase::ALIAS.'.admin_user_id,'.FilterBase::ALIAS.'.description,'.FilterBase::ALIAS.'.created_at,'.FilterBase::ALIAS.'.ip')
            ->setFirstResult(($page - 1) * $limit)
            ->setMaxResults($limit)
            ->orderBy(FilterBase::ALIAS.'.id', 'DESC')
            ->getQuery()
            ->getArrayResult();
    }

    /**
     * 获取指定用户最新的多条日志
     * @param $admin_user_id
     * @param int $limit
     * @return array|int|string
     */
    public function getWorkplaceTopLogs ($admin_user_id = null, $limit = 5) {
        $query = $this->createQueryBuilder('a')
            ->select('a.id,t.value as log_type_name,a.description,a.ip,u.avatar,u.username,a.created_at')
            ->leftJoin(AdminUser::class, 'u', 'with', 'u.id = a.admin_user_id')
            ->leftJoin(LogType::class, 't', 'with', 't.id = a.log_type_id')
            ->setFirstResult(0)
            ->setMaxResults($limit)
            ->orderBy('a.id', 'DESC')
            ->getQuery();
        if ($admin_user_id) {
            $query->where('a.admin_user_id = :admin_user_id')
                ->setParameter('admin_user_id', $admin_user_id);
        }

        return $query->getArrayResult();
    }

    /**
     * 获取查询count
     * @param array $params
     * @return int|mixed|string
     */
    public function searchTotal ($params = []) {
        return $this->filter(new LogFilter($params))
            ->select('count('.FilterBase::ALIAS.'.id) as total')
            ->getQuery()
            ->getSingleScalarResult();
    }
}
